package it.intecs.pisa.smarcos.services;

import it.intecs.pisa.smarcos.R;
import it.intecs.pisa.smarcos.activities.MenuNavigation;
import it.intecs.pisa.smarcos.base.BeepManager;
import it.intecs.pisa.smarcos.base.Extra;
import it.intecs.pisa.smarcos.base.GestureIntents;
import it.intecs.pisa.smarcos.base.SpeechManager;
import it.intecs.pisa.smarcos.base.XMLParser;
import it.intecs.pisa.smarcos.receivers.SMSReceivedBroadcastReceiver;
import it.intecs.pisa.smarcos.sounds.SoundEffects;
import it.intecs.pisa.smarcos.util.ContextUtils;
import it.intecs.pisa.smarcos.util.MathUtils;

import java.io.InputStream;
import java.util.ArrayList;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.OperationApplicationException;
import android.graphics.Color;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Vibrator;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.telephony.SmsManager;
import android.util.Log;

/**
 * This service takes care of handling all interaction with the user.
 *
 */
public class HumanInteractionService extends Service {

	public static final String INTENT_START="it.intecs.pisa.smarcos.services.HumanInteractionService.START";
	public static final String TAG = HumanInteractionService.class.getSimpleName();
	//static final int GESTURE_RESULT = 0;

	// TextToSpeech variables
	private SpeechManager speechManager;
	private IntentFilter ttsFilter;
	private TtsReadyReceiver TTSreceiver = null;
	private Vibrator vibrator;
	private BeepManager beepManager;
	private Boolean beepFlagLeft = false;
	private Boolean beepFlagRight = false;
	
	XMLParser parser;
	boolean parserOk = false;
	
	private ContextUtils cUtils;
	
	// Gesture Recognition variables
	boolean menuEnter = true;
	IntentFilter gestureFilter;
	private GestureRecognition gestureReceiver = null;
	
	// Result Receiver variables
	ArrayList<String> results = new ArrayList<String>();
	IntentFilter resultFilter;
	private ResultReceiver resultReceiver = null;
	
	IntentFilter smsReceiverFilter;
	private SMSReceivedBroadcastReceiver smsReceiver = null;

	public HumanInteractionService(){
		
		Log.d(TAG, "HumanInteractionService");
		
		// TtsReadyReceiver filter
        ttsFilter = new IntentFilter();
        ttsFilter.addAction("TTS READY");
        ttsFilter.addCategory(Intent.CATEGORY_DEFAULT);
        TTSreceiver = new TtsReadyReceiver();
               
        // GestureReceiver filter
        gestureFilter=new IntentFilter();
        gestureFilter.addAction(TAG + GestureIntents.INTENT_GESTURE_UP_MAIN);
        gestureFilter.addAction(TAG + GestureIntents.INTENT_GESTURE_UP);
        gestureFilter.addAction(TAG + GestureIntents.INTENT_GESTURE_DOWN);
        gestureFilter.addAction(TAG + GestureIntents.INTENT_GESTURE_LEFT);
        gestureFilter.addAction(TAG + GestureIntents.INTENT_GESTURE_RIGHT);
        gestureFilter.addAction(TAG + GestureIntents.INTENT_GESTURE_SELECT);
        gestureFilter.addCategory(Intent.CATEGORY_DEFAULT);      
        gestureReceiver=new GestureRecognition();
   
        // ResultReceiver filter
        resultFilter=new IntentFilter();
        resultFilter.addAction(ResultReceiver.INTENT_SHOW);
        resultFilter.addCategory(Intent.CATEGORY_DEFAULT);
        resultReceiver=new ResultReceiver();
        
        smsReceiverFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
        smsReceiverFilter.addCategory(Intent.CATEGORY_DEFAULT);
        smsReceiver = new SMSReceivedBroadcastReceiver();
	}
	
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	
	@Override
	public void onCreate() {

		Log.d(TAG, "onStartCommand");
		
		vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
		beepManager = BeepManager.getInstance(getApplicationContext());
		
		registerReceiver(TTSreceiver, ttsFilter);
		speechManager = SpeechManager.getInstance(this.getApplicationContext());
		cUtils = new ContextUtils(this.getApplicationContext());
		
		InputStream localFile = getBaseContext().getResources().openRawResource(R.raw.menu);
		parser = XMLParser.getInstance(getBaseContext(), localFile);
		if (parser.isParserOk()){

			parserOk = true;
			Log.d(TAG, "Parser ready");
			registerReceiver(gestureReceiver, gestureFilter);
			registerReceiver(resultReceiver, resultFilter);
		}
		
		SoundEffects.getInstance(getApplicationContext());
		
		registerReceiver(smsReceiver, smsReceiverFilter);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		Log.d(TAG, "onDestroy");
		
		unregisterReceiver(resultReceiver);
		unregisterReceiver(gestureReceiver);
		unregisterReceiver(TTSreceiver);
		
		if (isServiceRunning("it.intecs.pisa.smarcos.services.WirelessDiscoveryService")){
			Intent intent=new Intent(WirelessDiscoveryService.ISTART_SRV);
			intent.addCategory(Intent.CATEGORY_DEFAULT);
			stopService(intent);
		}

		SpeechManager.nullInstance();
		XMLParser.nullInstance();
	}
	
	private void changeMenuView(){
		try {
			Log.d(TAG, "changeMenuView");
			Intent layoutIntent;
			layoutIntent=new Intent("Update View");
			layoutIntent.putExtra("Step", "Standard");	
			layoutIntent.addCategory(Intent.CATEGORY_DEFAULT);					
			sendBroadcast(layoutIntent);
		} catch (Exception e) {
			Log.d(TAG, "" + e);
		}
	}
	
	private void changeMenuVoice(int color){
		try {
			Log.d(TAG, "changeMenuVoice");
			String entryToLightUp = parser.getAttributeValue(getString(R.string.MENU_ATTR_ETLU));
			Intent layoutIntent=new Intent("Update Background");

			Log.d(TAG, "-------- " + entryToLightUp);
			
			
			if (entryToLightUp.contains("Notification")){
				layoutIntent.putExtra("Id", MathUtils.convertToInteger(entryToLightUp.substring(12)));
				Log.d(TAG, "entryToLightUp " + entryToLightUp.substring(12));
			}else	
				layoutIntent.putExtra("Id", cUtils.retrieveRvalue("id", entryToLightUp.substring(5)));
			
			layoutIntent.putExtra("Color", color); 
			layoutIntent.addCategory(Intent.CATEGORY_DEFAULT);					
			sendBroadcast(layoutIntent);
		} catch (Exception e) {
			Log.d(TAG, "" + e);
		}
	}
		
	// BroadcastReceiver for TTS initialization
	private class TtsReadyReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context arg0, Intent recIntent) {
			Log.d(TAG, "OnReceive TTS ready");

			speechManager.say(getString(R.string.TTS_Ready), true, false);

			if (parserOk == false)
				speechManager.say(getString(R.string.TTS_Error_Msg), true, false);
			else  {
				Intent intent;
				intent=new Intent(MenuNavigation.INTENT_SHOW);
				intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
				intent.addCategory(Intent.CATEGORY_DEFAULT);
				intent.putExtra("ViewId", "main_menu");
				startActivity(intent);		
			}
		}
	}
	
	
	// BroadcastReceiver for gesture recognition
	private class GestureRecognition extends BroadcastReceiver {

		private final String LOG = GestureRecognition.class.getSimpleName();
			
		@Override
		public void onReceive(Context arg0, Intent intent) {

			String intentStr;

			intentStr=intent.getAction();
			Log.d(LOG , intentStr);

			if(intentStr.equals(TAG + GestureIntents.INTENT_GESTURE_SELECT)){

				vibrator.vibrate(100);
				if (parser.getAttributeType().equals("Leaf")) {
					Log.d(LOG , "is leaf");
					changeMenuVoice(getResources().getColor(R.color.LTBLUE));
					speechManager.say(cUtils.processString(parser.getAttributeValue(getString(R.string.MENU_ATTR_S2S))), true, true);
					
					if(parser.nodeHasChildren() > 0)
					{
						parser.changeRunningNode(GestureIntents.INTENT_GESTURE_SELECT);
						Fire();	
					}
				}else {

					menuEnter = true;
					changeMenuView();
					speechManager.say(cUtils.processString(parser.getAttributeValue(getString(R.string.MENU_ATTR_S2SM))), true, true);
				}
			}
			else if(intentStr.equals(TAG + GestureIntents.INTENT_GESTURE_UP)){
				menuEnter = true;
				ManageResults();
				parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP);
				changeMenuView();
				speechManager.say(cUtils.processString(parser.getAttributeValue(getString(R.string.MENU_ATTR_S2SM))), true, false);

			}else if(intentStr.equals(TAG + GestureIntents.INTENT_GESTURE_LEFT) || 
					intentStr.equals(TAG + GestureIntents.INTENT_GESTURE_RIGHT))
			{				
				if (menuEnter){
					menuEnter = false;
					parser.changeRunningNode(GestureIntents.INTENT_GESTURE_SELECT);
				} else
				{
					if (((beepFlagLeft.equals(true)) && intentStr.substring(TAG.length()).equals(GestureIntents.INTENT_GESTURE_RIGHT)) || 
						((beepFlagRight.equals(true)) && intentStr.substring(TAG.length()).equals(GestureIntents.INTENT_GESTURE_LEFT)))
					{
						beepFlagLeft = false;
						beepFlagRight = false;
					}else{
						
						//changeMenuVoice(Color.WHITE);
						changeMenuVoice(getResources().getColor(R.color.LTBLUE));
						if (!parser.changeRunningNode(intentStr.substring(TAG.length()))){
							beepManager.playBeepSound();
						}
					}
				}	
				//changeMenuVoice(Color.LTGRAY);
				changeMenuVoice(Color.RED);
				speechManager.say(cUtils.processString(parser.getAttributeValue(getString(R.string.MENU_ATTR_S2S))), false, false);
				/*if (parser.getAttributeValue(getString(R.string.MENU_ATTR_S2SM)) != null)
					speechManager.say(getString(R.string.TTS_SUB_MENU), false, true);*/
			}
			else if(intentStr.equals(TAG + GestureIntents.INTENT_GESTURE_UP_MAIN)){
				menuEnter = true;			
				parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP_MAIN);
				changeMenuView();
				speechManager.say(cUtils.processString(parser.getAttributeValue(getString(R.string.MENU_ATTR_S2SM))), true, false);
			}
		}
	}

	
	public class ResultReceiver extends BroadcastReceiver {

		public static final String INTENT_SHOW="it.intecs.pisa.smarcos.services.ResultReceiver.SHOW";
		private final String TAG = ResultReceiver.class.getSimpleName();

		@Override
		public void onReceive(Context arg0, Intent intent) {

			String result = intent.getStringExtra("Result");
			Log.d(TAG, "OnReceive - " + result);

			if (result.equals("NORESULT")) { // NORESULT PER ACTIVITY CHE NON PREVEDONO RISULTATO COME LA LETTURA DEGLI SMS O PER ACTIVITY TERMINATE CON IL BACK
				menuEnter = true;
				ManageResults();
				if (!parser.getAttributeValue("type").equals("Notification") &&
				   (!parser.getAttributeValue("type").equals("Menu"))){
					if (parser.getAttributeValue("nextNode").equals("GrandFather"))
						parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP);
					parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP);
					changeMenuView();
				}
			}
			else {
				results.add(result);	
				parser.changeRunningNode(GestureIntents.INTENT_GESTURE_RIGHT);
				Fire();
			}
		}		
	}

	private void ManageResults(){
		
		if (results == null || results.size() == 0)
			return;
		
		String toDo = parser.getAttributeValue("removeResults");
		if (toDo == null || toDo.length() == 0)
			return; 
		
		if (toDo.equals("All")){
			results.clear();
			return;
		}	
		
		if (toDo.equals("Last")){
			results.remove(results.size()-1);
			return;
		}	
	}
	
	private void Fire(){

		//LA FIRE GESTISCE 4 tipi di NODO: 1.ACTIVITY; 2.SERVICE; 3.COLLECT
		
		//1. lancia una activity
		//2. lancia un servizio
		//3. colleziona i risultati delle precedenti activity/service
		
		// LANCIA L'ACTIVITY/SERVICE CHE STA NEL PRIMO NODO FIGLIO		
		// L'ACTIVITY/SERVICE ALLA FINE DELLA SUA ESECUZIONE LANCIA UN INTENTE CON IL RISULTATO		
		// QUESTO INTENT VIENE RACCOLTO DAL BROADCAST RECEIVER ResultReceiver DEFINITO IN QUESTA CLASSE		
		// QUANDO IL ResultReceiver RICEVE IL RISULTATO CONTROLLA SE ESISTE UN NODO FRATELLO		
		// CHIAMA LA Fire() SUL NODO FRATELLO  
		
		Log.d(TAG, "Fire");	
		Extra[] extras;		
		String type = parser.getAttributeType();
		
		
		if (type.equals("Activity")) {
			
			String activityName = parser.getAttributeValue(getString(R.string.MENU_ATTR_AN));
			Intent intent;		
			intent=new Intent(activityName);
			Log.d(TAG, "Activity Intent " + activityName);

			int countResFromPrevious = 0;
			extras = parser.getExtras();
			if (extras != null){
				for (int i=0; i < extras.length; i++){	
					if (extras[i].getName().equals("ResultFromPrevious")){
						if (results.size() - countResFromPrevious != 0) {
							intent.putExtra(extras[i].getName(), results.get(results.size() - 1 - countResFromPrevious));
							countResFromPrevious++;
						}else {
							parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP);
							return;
						}
					}else
						intent.putExtra(extras[i].getName(), extras[i].getValue());
					Log.d(TAG, "Extra " + i + " " + extras[i].getName() + " = " + extras[i].getValue());
				}
			}		

			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // TO INVESTIGATE
			intent.addCategory(Intent.CATEGORY_DEFAULT);
			startActivity(intent);	
		}

		if (type.equals("Service")) {
			String serviceName = parser.getAttributeValue(getString(R.string.MENU_ATTR_SN));
			
			if ((parser.getAttributeValue("option")).equals("Start")) {

				if (isServiceRunning(serviceName)){
					speechManager.say("Wifi application feature already running", true, true);
				}else{
					Log.d(TAG, "Service Intent: START " + serviceName);
					Intent intent=new Intent(serviceName);
					intent.addCategory(Intent.CATEGORY_DEFAULT);
					startService(intent);
				}	
			}else if ((parser.getAttributeValue("option")).equals("Stop")) {
				Log.d(TAG, "Service Intent: STOP " + serviceName);
				if (isServiceRunning(serviceName)){
					speechManager.say("Wifi application feature stopped", true, true);
					Intent intent=new Intent(serviceName);
					intent.addCategory(Intent.CATEGORY_DEFAULT);
					stopService(intent);
				}else
					speechManager.say("Wifi application feature not running", true, true);
				
			}else if ((parser.getAttributeValue("option")).equals("Status")) {
				Log.d(TAG, "Service Intent: STATUS " + serviceName);
				wirelessStatus();
			}

			ManageResults();
			parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP);
			menuEnter = true;
		}
	

		if (type.equals("Collect")) {
			
			Collect(parser.getAttributeValue(getString(R.string.MENU_ATTR_COLL)));	
			ManageResults();
			parser.changeRunningNode(GestureIntents.INTENT_GESTURE_UP);
			menuEnter = true;
		}
		
		if (type.equals("Menu") || type.equals("Notification")) {
			
			Log.d(TAG, "Fire: Menu");
			menuEnter = true;
			changeMenuView();
		}
	}	
	
	
	private void Collect(String name){
		
		Log.d(TAG, "Collect " + name);
		
		if (name.equals("Phone")){
			speechManager.say(getString(R.string.TTS_CANNOT_Call), true, false);
			
			/*String numToCall = results.get(0);
			speechManager.say(getString(R.string.TTS_NP_Calling) + numToCall, true, false);
			Intent dialIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + numToCall));
			dialIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			startActivity(dialIntent);
			*/
		}
	
		if (name.equals("Write SMS")){
			String numDest = results.get(0);
			if (numDest.equals(null))
				speechManager.say("Null destination number, sending aborted", true, false);
			else{
				String textBody = results.get(1);
				SmsManager manager = SmsManager.getDefault();
				Log.d(TAG, numDest + " " + textBody);
				manager.sendTextMessage(numDest, null, textBody, null, null);
				speechManager.say(getString(R.string.TTS_SMS_SENT), true, false);
			}
		}

		if (name.equals("Add Contact")){
	
			Log.d(TAG, "Adding contact....");
			
			if (results.get(0) == null || results.get(0).length() == 0 ){
				speechManager.say(getString(R.string.TTS_Contact_EmptyName), true, false);
				return;
				
			}
						
			if (results.get(1) == null || results.get(1).length() == 0 ){
				speechManager.say(getString(R.string.TTS_Contact_EmptyNumber), true, false);
				return;
			}
			
			ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
            int rawContactInsertIndex = ops.size();

            ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
                    .withValue(RawContacts.ACCOUNT_TYPE, null)
                    .withValue(RawContacts.ACCOUNT_NAME, null).build());
            ops.add(ContentProviderOperation
                    .newInsert(Data.CONTENT_URI)
                    .withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)
                    .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
                    .withValue(StructuredName.DISPLAY_NAME, results.get(0)) // Name of the person
                    .build());
            ops.add(ContentProviderOperation
                    .newInsert(Data.CONTENT_URI)
                    .withValueBackReference(
                            ContactsContract.Data.RAW_CONTACT_ID,   rawContactInsertIndex)
                    .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                    .withValue(Phone.NUMBER, results.get(1)) // Number of the person
                    .withValue(Phone.TYPE, Phone.TYPE_MOBILE).build()); // Type of mobile number                    
            try
            {
                ContentProviderResult[] res = getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
                speechManager.say(getString(R.string.TTS_Contact_Added), true, false);
            }
            catch (RemoteException e)
            { 
                Log.d(TAG, "Add Contact: RemoteException " + e);// error
            }
            catch (OperationApplicationException e) 
            {
            	Log.d(TAG, "Add Contact: OperationApplicationException " + e);// error
            }       
			
		}
		

		Log.d(TAG, "Collect end");
	}
	
	private boolean isServiceRunning(String srvString) {
		Log.d(TAG, "isServiceRunning");
		
	    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
	    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
	    	Log.d(TAG, "Running service: " + service.service.getClassName());
	        if (srvString.equals(service.service.getClassName())) {
	            return true;
	        }
	    }
	    return false;
	}
	
	
	private void wirelessStatus(){
		
		Log.d(TAG, "wirelessStatus");
		
		if (isServiceRunning("it.intecs.pisa.smarcos.services.WirelessDiscoveryService")){
			speechManager.say("Wifi application feature is running", true, true);
		}else
			speechManager.say("Wifi application feature is not running", true, true);
		
		WifiManager mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		
		if (!mWifiManager.isWifiEnabled())
			speechManager.say("Wifi service is disabled", true, true);
		else{
			WifiInfo conInfo = mWifiManager.getConnectionInfo();
			speechManager.say("Wifi connection status is " + conInfo.getSupplicantState(), true, true);
		}
	}
	
}


	